package com.andova.camera.glsurface

import android.content.Context
import android.graphics.ImageFormat
import android.graphics.SurfaceTexture
import android.hardware.Camera
import android.opengl.GLSurfaceView
import com.andova.cameraview.CameraView
import com.andova.ext.e
import com.andova.ext.i
import com.andova.face.FaceUtil
import com.andova.face.ICameraCheckListener
import com.andova.face.IFaceDetector
import com.andova.face.detector.CameraProvider
import com.andova.face.detector.IPreview
import java.nio.ByteBuffer
import java.nio.ByteOrder

class ACameraBufferPreviewer(private val context: Context, private val preview: IPreview, private val viewport: GLSurfaceView,
                             private val surfaceTexture: SurfaceTexture? = SurfaceTexture(0)) {
    private var camera: Camera? = null
    private var checkListener: ICameraCheckListener? = null

    @CameraView.Facing
    private var cameraId: Int = 0
    private var orientation = -1
    private var cameraWidth: Int = 0
    private var cameraHeight: Int = 0
    private var minCameraPixel: Long = 0
    private var displayOrientation: Int = 0
    private val cameraProvider = CameraProvider()
    private var faceDetector: IFaceDetector? = null
    private var bufferY: ByteBuffer? = null
    private var bufferUV: ByteBuffer? = null
    private var bufferUpdated = false

    fun setFaceDetector(faceDetector: IFaceDetector?): IPreview = preview.apply { this@ACameraBufferPreviewer.faceDetector = faceDetector }
    fun setCheckListener(checkListener: ICameraCheckListener?): IPreview = preview.apply { this@ACameraBufferPreviewer.checkListener = checkListener }
    fun setMinCameraPixels(minCameraPixels: Long): IPreview = preview.apply { this@ACameraBufferPreviewer.minCameraPixel = minCameraPixels }
    fun setDisplayOrientation(degree: Int): IPreview = preview.apply { this@ACameraBufferPreviewer.orientation = degree }
    fun setCameraId(cameraId: Int): IPreview = preview.apply { this@ACameraBufferPreviewer.cameraId = cameraId }
    fun getCameraId(): Int = cameraId
    fun closeCamera() {
        faceDetector?.setOpenCamera(false)
        try {
            camera?.setPreviewCallback(null)
            camera?.stopPreview()
            camera?.release()
            camera = null
        } catch (ignore: Exception) {
        }
    }

    fun release() {
        closeCamera()
        faceDetector?.release()
    }

    fun openCamera() {
        camera?.run { return }
        if (!FaceUtil.checkCameraPermission(context)) {
            i("摄像头权限未打开，请打开后再试")
            checkListener?.checkPermission(false)
            return
        }
        // 只有一个摄相头，打开后置
        if (Camera.getNumberOfCameras() == 1) cameraId = CameraView.FACING_BACK
        faceDetector?.setCameraId(cameraId)
        try {
            camera = Camera.open(cameraId)
            // setParameters 针对部分手机通过Camera.open()拿到的Camera对象不为null
            val mParameters = camera?.parameters
            camera?.parameters = mParameters
            if (CameraView.FACING_FRONT == cameraId) i("前置摄像头已开启") else i("后置摄像头已开启")
        } catch (e: Exception) {
            e.printStackTrace()
            //回调权限判定结果
            checkListener?.checkPermission(false)
            //关闭相机
            closeCamera()
            return
        }
        camera ?: return
        //回调权限判定结果
        checkListener?.checkPermission(true)
        var pixels = 0L
        try {
            //获取最大宽高，得出最大支持像素
            val parameters = camera?.parameters
            // getSupportedPictureSizes：获取横屏模式下摄像头支持的PictureSize列表
            FaceUtil.findMaxCameraSize(parameters?.supportedPictureSizes)?.run { pixels = (this.width * this.height).toLong() }
            i("camera max support pixels: $pixels")
            //回调该手机像素值
            if (checkListener != null && minCameraPixel > 0) {
                if (pixels >= minCameraPixel) {
                    checkListener?.checkPixels(pixels, true)
                } else {
                    closeCamera()
                    checkListener?.checkPixels(pixels, false)
                    return
                }
            }
            i("camera size width:$cameraWidth,height:$cameraHeight")
            faceDetector?.setCameraWidth(cameraWidth)
            faceDetector?.setCameraHeight(cameraHeight)
            //设置相机参数
            displayOrientation = FaceUtil.setCameraParams(viewport, faceDetector, checkListener, null, camera, cameraId, cameraWidth, cameraHeight)
            i("camera getPreviewSize width:${camera?.parameters?.previewSize?.width},height:${camera?.parameters?.previewSize?.height}")
            i("camera getPictureSize width:${camera?.parameters?.pictureSize?.width},height:${camera?.parameters?.pictureSize?.height}")
            if (orientation != -1) camera?.setDisplayOrientation(orientation)
            startPreview()
        } catch (ex: Exception) {
            closeCamera()
            checkListener?.checkPixels(pixels, false)
            e("Error starting camera preview: $ex")
        }
    }

    private fun startPreview() {
        camera?.parameters?.previewFormat = ImageFormat.NV21
        val ySize = camera?.parameters?.previewSize?.run { width * height } ?: 0
        val bufSize = ySize * ImageFormat.getBitsPerPixel(ImageFormat.NV21) / 8
        val uvSize = bufSize - ySize
        bufferY = ByteBuffer.allocateDirect(ySize).order(ByteOrder.nativeOrder())
        bufferUV = ByteBuffer.allocateDirect(uvSize).order(ByteOrder.nativeOrder())
        camera?.addCallbackBuffer(ByteArray(bufSize))
        //设置预览回调
        camera?.setPreviewCallbackWithBuffer { data, camera ->
            faceDetector ?: return@setPreviewCallbackWithBuffer
            cameraProvider.previewWidth = camera.parameters.previewSize.width
            cameraProvider.previewHeight = camera.parameters.previewSize.height
            faceDetector?.setCameraPreviewData(data, cameraProvider)
            faceDetector?.setOpenCamera(true)

            bufferY?.position(0)
            bufferY?.put(data, 0, ySize)
            bufferUV?.position(0)
            bufferUV?.put(data, ySize, uvSize)
            camera.addCallbackBuffer(data)
            bufferUpdated(true)
        }
        camera?.setPreviewTexture(surfaceTexture)
        //开始预览
        camera?.startPreview()
    }

    fun bufferUpdated(): Boolean = bufferUpdated
    fun bufferUpdated(value: Boolean) = run { bufferUpdated = value }
    fun getBufferY() = bufferY
    fun getBufferUV() = bufferUV
    fun getCameraHeight(): Int = cameraHeight
    fun getCameraWidth(): Int = cameraWidth
    fun getPreviewWidth(): Int = camera?.parameters?.previewSize?.width ?: 0
    fun getPreviewHeight(): Int = camera?.parameters?.previewSize?.height ?: 0
    fun getDisplayOrientation(): Int = if (orientation == -1) displayOrientation else orientation
    fun getCamera(): Camera? = camera
}